package main;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class Main 
{
	public static ArrayList<MathFunction> func = new ArrayList<MathFunction>();
	
	
	public static void main(String[] args) 
	{
		BufferedReader d = new BufferedReader(new InputStreamReader(System.in));
		boolean bExit = false;

		if(args.length == 2)
		{
			doCommand(args[0], args);
		}
		else
		{
			while(!bExit)
			{
				
				try {
					String inp = "";
					
					while(inp == "\r\n" || inp.isEmpty())
						inp = d.readLine();
					
					
					if(inp.matches("exit"))
						bExit = true;
					else
					{
						Pattern p = Pattern.compile("\"([^\"]+)\"|\\s*?([^\"\\s]+)"); 
						Matcher m = p.matcher(inp);
						ArrayList<String> matches = new ArrayList<String>();
						
						while(m.find()){
						    matches.add(m.group().replace(" ", ""));
						}
						
						doCommand(matches.get(0), matches.toArray(new String[matches.size()]));
					}
						
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
	}
	
	
	static void doCommand(String command, String[] param)
	{
		switch(command)
		{
			case "calc":
				if(param.length == 2)
				{
					param[1] = param[1].replace("\"", "");
					
					for(int i=0; i < func.size(); i++)
						if(param[1].contains(func.get(i).name))
						{
							Pattern p = Pattern.compile(func.get(i).name + "\\((.*?)\\)"); 
							Matcher m = p.matcher(param[1]);
							while(m.find())
								param[1] = param[1].replace(m.group(0), Double.toString(func.get(i).getValueAt(Double.parseDouble(m.group(1)))));
						}
					
					System.out.println("Resultado: " + MathBasicArithmetic.eval(param[1]));
				}
				else
					System.out.println("Uso incorreto do comando 'calc'.\n\nModo de uso: calc <expressao>\n\nEx: \ncalc -2*(3+5)\n>>Resultado: -16\ncalc \"sin(pi / 2) + 3\"\n>>Resultado: 4");
				
				break;
			case "mbisseccao":
				if(param.length == 6)
				{
					MathFunction f = null;
					double a = 0;
					double b = 0;
					int kmax = 0;
					double tol = 0;
					
					String funcName = param[1];
					
					try
					{
						a = Double.parseDouble(param[2]);
						b = Double.parseDouble(param[3]);
						kmax = Integer.parseInt(param[4]);
						tol = Double.parseDouble(param[5]);
					}
					catch(Exception e)
					{
						System.out.println("'a, 'b', 'kmax', 'tol' tem de ser numeros.");
					}
					
					
					for(int i=0; i<func.size(); i++)
						if(func.get(i).name.contains(funcName))
							f = func.get(i);
					
					if(f == null)
					{
						System.out.println("A funcao '" + funcName + "' nao foi declarada. Use o comando defineFunction.");
						return;
					}
					
					if(f.getValueAt(a) * f.getValueAt(b) >= 0)
					{
						System.out.println("A funcao nao muda de sinal entre a e b.");
						return;
					}
					
					double x[] = f.getRootsBisect(f, a, b, kmax, tol);
					
					System.out.print("Resultado: ");
					
					for(int i=1; i < x[0] ; i++)
						System.out.print(x[i] + " ");
					
					System.out.print("\n");
				}
				else
				{
					System.out.println("Uso incorreto do comando 'mbisseccao'.\n\nModo de uso: mbisseccao <funcao> <a> <b> <kmax> <tol>\n\nEx: \ndeffunc f(x)=x^3-x-2\nmbisseccao f 1 2 3 0.1");
				}
				break;
				
			case "deffunc":				
				if(param.length == 2)
				{
					param[1] = param[1].replace("\"", "");
					Pattern p = Pattern.compile("([A-Za-z]*)\\(([A-Za-z])\\)=(.*)"); 
					Matcher m = p.matcher(param[1]);
					m.find();
					
					func.add(new MathFunction(m.group(3), m.group(1), m.group(2)));
					
				}
				else
					System.out.println("Uso incorreto do comando 'deffunc'.\n\nModo de uso: deffunc f(x)=x\n\nEx: \ndeffunc area(l)=l*l\ndeffunc radianos(graus)=(graus*pi)/180\ndeffunc f(x)=2*x^2+3x+4");
				break;
		
			/*case "help":
				break;*/
			
			default:
				System.out.println("Comando '" + command + "' não definido.");
				break;
		}
	}
	
	
	 
}
